﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.Serialization.Json;
using Newtonsoft.Json;
using System.Diagnostics;

namespace ExtractImagePoiJson
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {        
        private enum PoiColor { red, green, blue, yellow, black, skyblue, orange }
        private PoiColor[] colorList = { PoiColor.black, PoiColor.skyblue, PoiColor.red, PoiColor.yellow, PoiColor.green, PoiColor.blue, PoiColor.orange };
        private BitmapImage image;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.DefaultExt = ".png";
            dlg.Filter = "PNG Image|*.png";            
            if (dlg.ShowDialog() == true)
            {
                statusBarItem.Content = "正在解析点阵...";
                // Open document 
                string filename = dlg.FileName;                
                //Stopwatch sw = new Stopwatch();
                //sw.Restart();
                byte[] pixels = this.getPixels(filename);
                //sw.Stop();
                //long t1 = sw.ElapsedMilliseconds;
                //sw.Restart();
                Dictionary<string, List<Dictionary<string, int>>> result = getPoiList(pixels);
                this.drawDricleList(result);
                string json = JsonConvert.SerializeObject(result);                
                //Clipboard.SetText(json);
                string jsonfilename = saveFile(json, filename);
                statusBarItem.Content = "解析点阵完毕，结果已保存到[" + jsonfilename + "]";
                this.Title = System.IO.Path.GetFileNameWithoutExtension(filename);
                //sw.Stop();
                //long t2 = sw.ElapsedMilliseconds;
                //this.Title = "t1:" + t1 + ";t2:" + t2;
                //MessageBox.Show(filename);
            }
        }

        private string saveFile(string json, string imagefilefullname)
        {
            try
            {
                string imagefilename = System.IO.Path.GetFileNameWithoutExtension(imagefilefullname);
                String appStartupPath = System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
                string jsonfilename = appStartupPath + '\\' + imagefilename + ".json";
                FileStream xiaFile = new FileStream(jsonfilename, FileMode.Create);
                try
                {
                    byte[] buf = Encoding.UTF8.GetBytes(json);
                    xiaFile.Write(buf, 0, buf.Length);
                    xiaFile.Flush();
                }
                finally
                {
                    xiaFile.Close();
                }
                return jsonfilename;
            }
            catch(Exception e)
            {
                statusBarItem.Content = "保存文件失败:" + e.Message;
                throw e;
            }
        }

        private byte[] getPixels(string fileName)
        {
            image = new BitmapImage(new Uri(fileName, UriKind.Absolute));
            pngImage.Source = image;
            int stride = image.PixelWidth * 4;
            int size = image.PixelHeight * stride;
            byte[] pixels = new byte[size];
            image.CopyPixels(pixels, stride, 0);
            return pixels;
        }

        private Dictionary<string, List<Dictionary<string, int>>> getPoiList(byte[] pixels)
        {
            Dictionary<string, List<Dictionary<string, int>>> result = new Dictionary<string, List<Dictionary<string, int>>>();
            int resultIndex = 1;
            for (var i = 0; i < this.colorList.Length; i++)
            {
                var item = this.getPoiListColor(pixels, this.colorList[i]);
                if (item.Count > 0)
                    result.Add("区域" + (resultIndex++), item);
            }
            return result;
            
            /*console.log(dojo.toJson(result));
            Dictionary<string, int> result = new Dictionary<string, int>();
            result.Add("区域1", 1);
            result.Add("区域2", 3);*/
            /*MemoryStream stream1 = new MemoryStream();
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Dictionary<string, int>));
            ser.WriteObject(stream1, result);
            stream1.Position = 0;
            StreamReader sr = new StreamReader(stream1);
            MessageBox.Show(sr.ReadToEnd());*/
            
            //MessageBox.Show(json);
        }

        private List<Dictionary<string, int>> getPoiListColor(byte[] pixels, PoiColor color)
        {
            byte[] imgData = (byte[])pixels.Clone();
            for (var i = 0; i < imgData.Length; i += 4)
            {
                if (imgData[i + 3] == 2 || imgData[i + 3] == 3)
                {
                    imgData[i + 3] = 4;
                    //console.log("error");
                    //continue;   
                }
                if (this._isGet(imgData, i, color))
                {
                    //imgData.data[i] = 255;
                    //imgData.data[i+1] = 0;
                    //imgData.data[i+2] = 0;
                    imgData[i + 3] = 2;
                }
            }
            var twoDivArray = this.getTwoDivArray(imgData);
            List<Dictionary<char, int>> result = this.searchAllPoi(twoDivArray);            
            return this.toJsonFormat(result);
            //console.log(dojo.toJson(result));
            //this._context.putImageData(imgData, 0, 0);
        }

        // red,green,blue,yellow,black,skyblue
        private bool _isGet(byte[] imgData, int i, PoiColor color)
        {
            if (color == PoiColor.red && imgData[i + 2] == 255 && imgData[i + 1] == 0 && imgData[i] == 0 && imgData[i + 3] == 255)
            {
                return true;
            }
            else if (color == PoiColor.green && imgData[i + 2] == 0 && imgData[i + 1] == 255 && imgData[i] == 60 && imgData[i + 3] == 255)
            {
                return true;
            }
            else if (color == PoiColor.blue && imgData[i + 2] == 42 && imgData[i + 1] == 0 && imgData[i] == 255 && imgData[i + 3] == 255)
            {
                return true;
            }
            else if (color == PoiColor.yellow && imgData[i + 2] == 255 && imgData[i + 1] == 234 && imgData[i] == 0 && imgData[i + 3] == 255)
            {
                return true;
            }
            else if (color == PoiColor.black && imgData[i + 2] == 0 && imgData[i + 1] == 0 && imgData[i] == 0 && imgData[i + 3] == 255)
            {
                return true;
            }
            else if (color == PoiColor.skyblue && imgData[i + 2] == 0 && imgData[i + 1] == 204 && imgData[i] == 255 && imgData[i + 3] == 255)
            {
                return true;
            }
            else if (color == PoiColor.orange && imgData[i + 2] == 254 && imgData[i + 1] == 101 && imgData[i] == 34 && imgData[i + 3] == 255)
            {
                return true;
            }
            else
                return false;
        }

        private byte[][][] getTwoDivArray(byte[] imgData)
        {
            byte[][][] twoDivArray = new byte[this.image.PixelHeight][][];
            int twoDivArrayIndex = 0;
            byte[][] oneDivArray = new byte[this.image.PixelWidth][];
            int oneDivArrayIndex = 0;
            for (var i = 0; i < imgData.Length; i += 4)
            {
                oneDivArray[oneDivArrayIndex++] = new byte[]{ imgData[i], imgData[i + 1], imgData[i + 2], imgData[i + 3]};                   
                if (oneDivArrayIndex == this.image.PixelWidth)
                {
                    twoDivArray[twoDivArrayIndex++] = oneDivArray;
                    oneDivArray = new byte[this.image.PixelWidth][];
                    oneDivArrayIndex = 0;
                }
            }
            return twoDivArray;
        }

        private List<Dictionary<char, int>> searchAllPoi(byte[][][] imgData)
        {
            //console.log("imgData.length:" + imgData.length + ";this._element.height:" + this._element.height);
            //console.log("searchAllPoi:" + dojo.toJson(imgData)); 
            List<List<Dictionary< char, int>>> resultList = new List<List<Dictionary<char, int>>>();
            for (var i = 0; i < imgData.Length; i++)
            {
                //console.log("imgData[i]:" + dojo.toJson(imgData[i]));
                for (var j = 0; j < imgData[i].Length; j++)
                {
                    var pixel = imgData[i][j];
                    //console.log("pixel:" + dojo.toJson(pixel));
                    if (pixel[3] == 2)
                    {
                        //console.log("i:" + i + ";j:" + j);
                        //this._drawCircle(j, i);
                        //return [];
                        List<Dictionary<char, int>> result = new List<Dictionary<char, int>>();
                        this.searchPoi(imgData, result, i, j);
                        resultList.Add(result);
                    }
                }
            }
            //resultList = this.computePoiLoc(resultList);
            //console.log("searchAllPoi:" + dojo.toJson(resultList)); 
            return this.computePoiLoc(resultList);
        }

        private void searchPoi(byte[][][] imgData, List<Dictionary<char, int>> result, int i, int j)
        {
            if (i >= 0 && i < this.image.PixelWidth && j >= 0 && j < this.image.PixelHeight
                && imgData[i][j][3] == 2)
            {
                Dictionary<char, int> item = new Dictionary<char, int>();
                item.Add('i', i);
                item.Add('j', j);
                result.Add(item);
                imgData[i][j][3] = 3;
                this.searchPoi(imgData, result, i - 1, j);
                this.searchPoi(imgData, result, i + 1, j);
                this.searchPoi(imgData, result, i, j - 1);
                this.searchPoi(imgData, result, i, j + 1);
            }
        }

        private List<Dictionary<char, int>> computePoiLoc(List<List<Dictionary<char, int>>> resultList)
        {
            //console.log("computePoiLoc.resultList:" + dojo.toJson(resultList));
            List<Dictionary<char, int>> result = new List<Dictionary<char, int>>();
            for (var i = 0; i < resultList.Count; i++)
            {
                if (resultList[i].Count < 190 || resultList[i].Count > 200)
                    continue;
                int totali = 0, totalj = 0;
                for (int j = 0; j < resultList[i].Count; j++)
                {
                    totali = totali + resultList[i][j]['i'];
                    totalj = totalj + resultList[i][j]['j'];
                }
                Dictionary<char, int> item = new Dictionary<char, int>();
                item.Add('i', (int)Math.Truncate((double)totali / (double)resultList[i].Count + 0.5));
                item.Add('j', (int)Math.Truncate((double)totalj / (double)resultList[i].Count + 0.5));
                result.Add(item);                
            }
            return result;
        }

        private List<Dictionary<string, int>> toJsonFormat(List<Dictionary<char, int>> data)
        {
            List<Dictionary<string, int>> result = new List<Dictionary<string, int>>();
            for (var i = 0; i < data.Count; i++)
            {
                Dictionary<string, int> item = new Dictionary<string, int>();
                item.Add("left", data[i]['j']);
                item.Add("top", data[i]['i']);
                item.Add("status", 1);
                result.Add(item);
            }
            return result;
        }

        private void _drawCircle(int i, int j)
        {
            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();
            drawingContext.DrawImage(pngImage.Source, new Rect(0, 0, image.PixelWidth, image.PixelHeight));
            SolidColorBrush mySolidColorBrush = new SolidColorBrush();
            mySolidColorBrush.Color = Color.FromArgb(255, 0, 125, 125);
            drawingContext.DrawEllipse(mySolidColorBrush, new Pen(), new Point(i, j), 3, 3);
            drawingContext.Close();
            RenderTargetBitmap bmp = new RenderTargetBitmap(this.image.PixelWidth, this.image.PixelHeight, this.image.DpiX, this.image.DpiY, PixelFormats.Pbgra32);
            bmp.Render(drawingVisual);
            pngImage.Source = bmp;
            //WriteableBitmap writeableBitmap = new WriteableBitmap(image);
            //writeableBitmap.
        }

        private void drawDricleList(Dictionary<string, List<Dictionary<string, int>>> result)
        {
            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();
            drawingContext.DrawImage(image, new Rect(0, 0, image.PixelWidth, image.PixelHeight));
            SolidColorBrush mySolidColorBrush = new SolidColorBrush();
            mySolidColorBrush.Color = Color.FromArgb(255, 0, 125, 125);
            Pen pen = new Pen();
            foreach (var list in result.Values)
            {
                for (var i = 0; i < list.Count; i++)
                {
                    drawingContext.DrawEllipse(mySolidColorBrush, new Pen(), new Point(list[i]["left"], list[i]["top"]), 3, 3);
                }
            }
            drawingContext.Close();
            RenderTargetBitmap bmp = new RenderTargetBitmap(this.image.PixelWidth, this.image.PixelHeight, this.image.DpiX, this.image.DpiY, PixelFormats.Pbgra32);
            bmp.Render(drawingVisual);
            pngImage.Source = bmp;
        }
    }
}
